#include <stdio.h>
#include <malloc.h>
#include <string.h>
#include "Info.c"
#include "StringUtil.h"

#define BSWAP_16(x) \
    (uint_16)((((uint_16)(x) & 0x00ff) << 8) | \
              (((uint_16)(x) & 0xff00) >> 8) \
             )
#define BSWAP_32(x) \
    (uint_32)((((uint_32)(x) & 0xff000000) >> 24) | \
              (((uint_32)(x) & 0x00ff0000) >> 8) | \
              (((uint_32)(x) & 0x0000ff00) << 8) | \
              (((uint_32)(x) & 0x000000ff) << 24) \
             )
typedef unsigned int uint_32;
typedef unsigned short uint_16;
typedef unsigned char u1;
//typedef map<int,char*> Map;
typedef struct {
    int i1;
    int i2;
} test;


struct constant_pool {
    u1 tag;
    char *info;

    struct constant_pool *(*new)(char *tmp, u1 tag, int length);

    void (*parse_constant_utf8)(struct constant_pool *constant_pool, char *content, int *index);

    void (*parse_constant_unicode)(struct constant_pool *constant_pool, char *content, int *index);

    void (*parse_constant_integer)(struct constant_pool *constant_pool, char *content, int *index);

    void (*parse_constant_float)(struct constant_pool *constant_pool, char *content, int *index);

    void (*parse_constant_long)(struct constant_pool *constant_pool, char *content, int *index);

    void (*parse_constant_double)(struct constant_pool *constant_pool, char *content, int *index);

    void (*parse_constant_class)(struct constant_pool *constant_pool, char *content, int *index);

    void (*parse_constant_string)(struct constant_pool *constant_pool, char *content, int *index);

    void (*parse_constant_fieldref)(struct constant_pool *constant_pool, char *content, int *index);

    void (*parse_constant_methodref)(struct constant_pool *constant_pool, char *content, int *index);

    void (*parse_constant_nameandtype)(struct constant_pool *constant_pool, char *content, int *index);
};

char *readLength(const char *content, int *from, int length);

char *readU2(const char *content, int *from);

char *readU4(const char *content, int *from);

struct constant_pool *new(char *tmp, u1 tag, int length);

void parse_constant_utf8(struct constant_pool *constant_pool, char *content, int *index);

void parse_constant_unicode(struct constant_pool *constant_pool, char *content, int *index);

void parse_constant_integer(struct constant_pool *constant_pool, char *content, int *index);

void parse_constant_float(struct constant_pool *constant_pool, char *content, int *index);

void parse_constant_long(struct constant_pool *constant_pool, char *content, int *index);

void parse_constant_double(struct constant_pool *constant_pool, char *content, int *index);

void parse_constant_class(struct constant_pool *constant_pool, char *content, int *index);

void parse_constant_string(struct constant_pool *constant_pool, char *content, int *index);

void parse_constant_fieldref(struct constant_pool *constant_pool, char *content, int *index);

void parse_constant_methodref(struct constant_pool *constant_pool, char *content, int *index);

void parse_constant_interfacemethodref(struct constant_pool *constant_pool, char *content, int *index);

void parse_constant_nameandtype(struct constant_pool *constant_pool, char *content, int *index);

char *loadFile(char *path);

enum {
    CONSTANT_Utf8 = 1,
    CONSTANT_Unicode,   //not used
    CONSTANT_Integer,
    CONSTANT_Float,
    CONSTANT_Long,
    CONSTANT_Double,
    CONSTANT_Class,
    CONSTANT_String,
    CONSTANT_Fieldref,
    CONSTANT_Methodref,
    CONSTANT_InterfaceMethodref,
    CONSTANT_NameAndType,
};

struct constant_pool pool = {
        .new=new,
        .parse_constant_utf8=parse_constant_utf8,
        .parse_constant_unicode=parse_constant_unicode,
        .parse_constant_integer=parse_constant_integer,
        .parse_constant_long=parse_constant_long,
        .parse_constant_double=parse_constant_double,
        .parse_constant_class=parse_constant_class,
        .parse_constant_string=parse_constant_string,
        .parse_constant_fieldref=parse_constant_fieldref,
        .parse_constant_methodref=parse_constant_methodref,
        .parse_constant_nameandtype=parse_constant_nameandtype
};

struct constant_pool *new(char *tmp, u1 tag, int length) {
    struct constant_pool *constant_pool = NULL;
    int index = 0;
    while (length > index+1) {
        tag = *(readLength(tmp, &index, 1));
        INFO_PRINT("INDEX 指针位置:%x,数字:%d tag:%d\n",&index,index,tag);
        switch (tag) {

            case CONSTANT_Utf8:
                parse_constant_utf8(constant_pool, tmp, &index);
                break;
            case CONSTANT_Unicode:
                parse_constant_unicode(constant_pool, tmp, &index);
                break;
            case CONSTANT_Integer:
                parse_constant_integer(constant_pool, tmp, &index);
                break;
            case CONSTANT_Float:
                parse_constant_float(constant_pool, tmp, &index);
                break;
            case CONSTANT_Long:
                parse_constant_long(constant_pool, tmp, &index);
                break;
            case CONSTANT_Double:
                parse_constant_double(constant_pool, tmp, &index);
                break;
            case CONSTANT_Class:
                parse_constant_class(constant_pool, tmp, &index);
                break;
            case CONSTANT_String:
                parse_constant_string(constant_pool, tmp, &index);
                break;
            case CONSTANT_Fieldref:
                parse_constant_fieldref(constant_pool, tmp, &index);
                break;
            case CONSTANT_Methodref:
                parse_constant_methodref(constant_pool, tmp, &index);
                break;
            case CONSTANT_InterfaceMethodref:
                parse_constant_interfacemethodref(constant_pool, tmp, &index);
                break;
            case CONSTANT_NameAndType:
                parse_constant_nameandtype(constant_pool, tmp, &index);
                break;
            default:
                return NULL;
        }
    }
    return constant_pool;
}

void parse_constant_utf8(struct constant_pool *constant_pool, char *content, int *index) {
    char *length = readU2(content, index);
    short realLength = BSWAP_16(*length);
    char *utf8_pool = readLength(content, index, realLength);

//    char *str = StringUtil.newString(BSWAP_16(*length),utf8_pool);
    INFO_PRINT("当前字符串%c\n",(unsigned char )*utf8_pool);
}

void parse_constant_unicode(struct constant_pool *constant_pool, char *content, int *index) {

}

void parse_constant_integer(struct constant_pool *constant_pool, char *content, int *index) {

}

void parse_constant_float(struct constant_pool *constant_pool, char *content, int *index) {

}

void parse_constant_long(struct constant_pool *constant_pool, char *content, int *index) {

}

void parse_constant_double(struct constant_pool *constant_pool, char *content, int *index) {

}

void parse_constant_class(struct constant_pool *constant_pool, char *content, int *index) {
    readU2(content,index);
}

void parse_constant_string(struct constant_pool *constant_pool, char *content, int *index) {
    readU2(content,index);
}

void parse_constant_fieldref(struct constant_pool *constant_pool, char *content, int *index) {
    readU4(content,index);
}

void parse_constant_methodref(struct constant_pool *constant_pool, char *content, int *index) {
    readU4(content,index);
}

void parse_constant_interfacemethodref(struct constant_pool *constant_pool, char *content, int *index) {

}

void parse_constant_nameandtype(struct constant_pool *constant_pool, char *content, int *index) {

}

test *func_char() {
    return malloc(sizeof(test));
}

char *readLength(const char *content, int *from, int length) {
    char *ret = (char *) calloc(length, sizeof(char));
    for (int i = 0; i < length; i++) {
        ret[i] = *(content + *from);
        (*from)++;
    }
    return ret;
}

char *readU4(const char *content, int *from) {
    return readLength(content, from, 4);

}

char *readU2(const char *content, int *from) {
    return readLength(content, from, 2);
}

char *readU1(const char *content, int *from) {
    return readLength(content, from, 1);
}


int main() {
    char *tmp = loadFile("/home/ouka/学习/hotspot/class-file/Test.class");
    int num = 0;
    int *index = &num;
    int *magic = (int *) readU4(tmp, index);
    INFO_PRINT("magic:%x \n", BSWAP_32(*magic));
    short *minor = (short *) readU2(tmp, index);
    INFO_PRINT("minor:%x \n", BSWAP_16(*minor));
    short *major = (short *) readU2(tmp, index);
    INFO_PRINT("major:%x \n", BSWAP_16(*major));
    short *constantpoollegth = (short *) readU2(tmp, index);
    INFO_PRINT("contantpoollegth:%d \n", BSWAP_16(*constantpoollegth));
    INFO_PRINT("contantpoollegth:%x \n", BSWAP_16(*constantpoollegth));
    char *constant_pool = readLength(tmp, index, *constantpoollegth);
    int constant_pool_length = 0;
    struct constant_pool *constant_pool_domain = new(constant_pool, 1, *constantpoollegth);
//    char *tag = readU1(constant_pool, &constant_pool_length);
//    INFO_PRINT("tag:%x \n", *tag);
    return 0;
    //    StringUtil.newString(3,);
    //    String  str = StringUtil.newString(4, 1, 2, 3, 5);
//    printf("%s",str);

//    Array_t *array;
//    String str = StringUtil.newString(2, "12", "32");
//    StringUtil.split(str, "2", array);
//    INFO_PRINT("产生的字符 %s \n", str);
//    INFO_PRINT("产生的字符2 %d \n", StringUtil.split(str, "2", array));
//    stringUtilTest();
//    test test1[5];
//    func_char()[0].i1 = 1;
//    int aa = 222;
//    int o = 0x1414;
//    const int *oo = &o;
//    oo = &aa;
//    printf("%x \n", o);
//    PRINT("%x\n", o);
//    char *ooo = (char *) oo;
//    *ooo = 0x10;
//    printf("%x \n", o);
//    char a = 0x1; //
//    printf("a-->%x\n", a);
//    char *b = &a;
//    printf("b-->%x\n", b);
//    printf("*b-->%x\n", *b);
//    *b = 0x2;
//    char **c = &b;
//    printf("c-->%x\n", c);
//    char d = **c;
//    printf("d-->%x\n", d);
//    b = b + 1;
//    printf("b-->%x\n", b);
//    printf("*b-->%x\n", *b);
//
//    printf("--------------------\n");
//    printf("a:%x,&a:%x,*b:%x,b:%x,c:%x,*c:%x,d:%x\n", a, &a, *b, b, c, *c, d);

}

char *loadFile(char *path) {
    FILE *fp;
    fp = fopen(
            path,
            "r");
    fseek(fp, 0, SEEK_END);
    long file_size;
    file_size = ftell(fp);
    printf("%d", file_size);
    char *tmp;
    fseek(fp, 0, SEEK_SET);
    tmp = (char *) malloc(file_size * sizeof(char));
    fread(tmp, file_size, sizeof(char), fp);
    fclose(fp);
    return tmp;
}